﻿namespace ImapComponent.Net.Mail.Security
{
    using System.Net.Security;
    using System.Security.Authentication;
    using System.Security.Cryptography.X509Certificates;

    /// <summary>
    /// This class provides the ssl authentication.
    /// </summary>
    public class SslHandShake
    {
        #region Fields

        private readonly string targetHost;
        private readonly SslProtocols enabledSslProtocols = SslProtocols.Default;
        private readonly RemoteCertificateValidationCallback serverCertificateValidationCallback;
        private readonly LocalCertificateSelectionCallback clientCertificateValidationCallback;
        private readonly X509CertificateCollection clientCertificates;
        private readonly bool checkCertificateRevocation;

        #endregion // Fields

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the SslHandShake class.
        /// </summary>
        /// <param name="targetHost">The name of the server that will share SslStream.</param>
        /// <param name="enabledSslProtocols">The SslProtocols value that represents the protocol used for authentication.</param>
        /// <param name="serverCertificateValidationCallback">A RemoteCertificateValidationCallback delegate responsible for validating the certificate supplied by the remote party.</param>
        /// <param name="clientCertificateValidationCallback">A LocalCertificateSelectionCallback delegate responsible for selecting the certificate used for authentication.</param>
        /// <param name="clientCertificates">The X509CertificateCollection that contains client certificates.</param>
        /// <param name="checkCertificateRevocation">A Boolean value that specifies whether the certificate revocation list is checked during authentication.</param>
        public SslHandShake(string targetHost, SslProtocols enabledSslProtocols, RemoteCertificateValidationCallback serverCertificateValidationCallback, LocalCertificateSelectionCallback clientCertificateValidationCallback, X509CertificateCollection clientCertificates, bool checkCertificateRevocation)
        {
            this.targetHost = targetHost;
            this.enabledSslProtocols = enabledSslProtocols;
            this.clientCertificates = clientCertificates;
            this.serverCertificateValidationCallback = serverCertificateValidationCallback;
            this.clientCertificateValidationCallback = clientCertificateValidationCallback;
            this.checkCertificateRevocation = checkCertificateRevocation;
        }

        /// <summary>
        /// Initializes a new instance of the SslHandShake class.
        /// </summary>
        /// <param name="targetHost">The name of the server that will share SslStream.</param>
        /// <param name="enabledSslProtocols">The SslProtocols value that represents the protocol used for authentication.</param>
        /// <param name="serverCertificateValidationCallback">A RemoteCertificateValidationCallback delegate responsible for validating the certificate supplied by the remote party.</param>
        /// <param name="clientCertificateValidationCallback">A LocalCertificateSelectionCallback delegate responsible for selecting the certificate used for authentication.</param>
        /// <param name="clientCertificates">The X509CertificateCollection that contains client certificates.</param>
        public SslHandShake(string targetHost, SslProtocols enabledSslProtocols, RemoteCertificateValidationCallback serverCertificateValidationCallback, LocalCertificateSelectionCallback clientCertificateValidationCallback, X509CertificateCollection clientCertificates)
            : this(targetHost, enabledSslProtocols, serverCertificateValidationCallback, clientCertificateValidationCallback, clientCertificates, false)
        {
        }

        /// <summary>
        /// Initializes a new instance of the SslHandShake class.
        /// </summary>
        /// <param name="targetHost">The name of the server that will share SslStream.</param>
        /// <param name="enabledSslProtocols">The SslProtocols value that represents the protocol used for authentication.</param>
        /// <param name="serverCertificateValidationCallback">A RemoteCertificateValidationCallback delegate responsible for validating the certificate supplied by the remote party.</param>
        /// <param name="clientCertificateValidationCallback">A LocalCertificateSelectionCallback delegate responsible for selecting the certificate used for authentication.</param>
        public SslHandShake(string targetHost, SslProtocols enabledSslProtocols, RemoteCertificateValidationCallback serverCertificateValidationCallback, LocalCertificateSelectionCallback clientCertificateValidationCallback)
            : this(targetHost, enabledSslProtocols, serverCertificateValidationCallback, clientCertificateValidationCallback, null, false)
        {
        }

        /// <summary>
        /// Initializes a new instance of the SslHandShake class.
        /// </summary>
        /// <param name="targetHost">The name of the server that will share SslStream.</param>
        /// <param name="enabledSslProtocols">The SslProtocols value that represents the protocol used for authentication.</param>
        /// <param name="serverCertificateValidationCallback">A RemoteCertificateValidationCallback delegate responsible for validating the certificate supplied by the remote party.</param>
        public SslHandShake(string targetHost, SslProtocols enabledSslProtocols, RemoteCertificateValidationCallback serverCertificateValidationCallback)
            : this(targetHost, enabledSslProtocols, serverCertificateValidationCallback, null, null, false)
        {
        }

        /// <summary>
        /// Initializes a new instance of the SslHandShake class.
        /// </summary>
        /// <param name="targetHost">The name of the server that will share SslStream.</param>
        /// <param name="enabledSslProtocols">The SslProtocols value that represents the protocol used for authentication.</param>
        public SslHandShake(string targetHost, SslProtocols enabledSslProtocols)
            : this(targetHost, enabledSslProtocols, null, null, null, false)
        {
        }

        /// <summary>
        /// Initializes a new instance of the SslHandShake class.
        /// </summary>
        /// <param name="targetHost">The name of the server that will share SslStream.</param>
        public SslHandShake(string targetHost)
            : this(targetHost, SslProtocols.Default, null, null, null, false)
        {
        }

        #endregion // Constructors

        #region Properties

        /// <summary>
        /// Gets the name of the server that will share SslStream.
        /// </summary>
        public string TargetHost
        {
            get
            {
                return this.targetHost;
            }
        }

        /// <summary>
        /// Gets the SslProtocols value that represents the protocol used for authentication.
        /// </summary>
        public SslProtocols EnabledSslProtocols
        {
            get
            {
                return this.enabledSslProtocols;
            }
        }

        /// <summary>
        /// Gets a RemoteCertificateValidationCallback delegate responsible for validating the certificate supplied by the remote party.
        /// </summary>
        public RemoteCertificateValidationCallback ServerCertificateValidationCallback
        {
            get
            {
                return this.serverCertificateValidationCallback;
            }
        }

        /// <summary>
        /// Gets a LocalCertificateSelectionCallback delegate responsible for selecting the certificate used for authentication.
        /// </summary>
        public LocalCertificateSelectionCallback ClientCertificateValidationCallback
        {
            get
            {
                return this.clientCertificateValidationCallback;
            }
        }

        /// <summary>
        /// Gets the X509CertificateCollection that contains client certificates.
        /// </summary>
        public X509CertificateCollection ClientCertificates
        {
            get
            {
                return this.clientCertificates;
            }
        }

        /// <summary>
        /// Gets a value indicating whether the certificate revocation list is checked during authentication.
        /// </summary>
        public bool CheckCertificateRevocation
        {
            get
            {
                return this.checkCertificateRevocation;
            }
        }

        #endregion // Properties
    }
}
